package com.application.spider.model;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.log4j.Logger;

import com.application.spider.entities.alias.AttributeDataType;
import com.application.spider.entities.alias.DataType;
import com.application.spider.entities.regex.ItemRegex;
import com.application.spider.exception.ItemNotFoundException;
import com.application.spider.model.alias.ManagerSinonimos;

public class RetrivierWeb {
	
	protected ManagerSinonimos		managerSinonimos;
	protected DataType				dataType;
	protected Logger 				logger;
	
	public RetrivierWeb(ManagerSinonimos managerSinonimos) {
		logger = Logger.getLogger(getClass());
		this.managerSinonimos = managerSinonimos;
	}

	public String getWebPageContent(String url, String page,String regexPage, Integer grupoId, String charset) {
		String value = "";
		BufferedReader in = null;
//		boolean begin = false;

		DefaultHttpClient httpclient = new DefaultHttpClient();
		try {
			HttpHost target = new HttpHost(url, 80, "http");
//			HttpHost target = new HttpHost(url);
			HttpGet req = new HttpGet(page);

			logger.debug("executing request to " + target);

			HttpResponse rsp = httpclient.execute(target, req);
			HttpEntity entity = rsp.getEntity();

			logger.debug("----------------------------------------");
			logger.debug(rsp.getStatusLine());
			Header[] headers = rsp.getAllHeaders();
			for (int i = 0; i < headers.length; i++) {
				logger.info(headers[i]);
				if(headers[i].getName().equalsIgnoreCase("Content-Type")){
					for(HeaderElement element :headers[i].getElements()){
						for(NameValuePair nameValuePair :element.getParameters()){
							if(nameValuePair.getName().equalsIgnoreCase("charset")){
								charset = nameValuePair.getValue();		
							}
						}						
					}						
				}
			}
			
			logger.debug("----------------------------------------");
			if (charset == null || charset.isEmpty()) {
				charset = "utf-8";
			}

			if (entity != null) {
				StringBuffer stringBuffer = new StringBuffer();
				in = new BufferedReader(new InputStreamReader(entity.getContent(), charset));
				String inputLine;
				while ((inputLine = in.readLine()) != null) {
					logger.debug(inputLine);
					stringBuffer.append(inputLine+"\n");
//					if (begin && endPatter != null && inputLine.contains(endPatter)) {
//						break;
//					}
//					if (beginPatter == null || inputLine.contains(beginPatter)) {
//						begin = true;
//					}
//					if (begin) {
//						value += inputLine;
//					}
				}
				Pattern     	pattern = null;
		        Matcher     	matcher = null;		        
		        
		        pattern = Pattern.compile(regexPage, Pattern.CASE_INSENSITIVE|Pattern.MULTILINE|Pattern.DOTALL|Pattern.UNICODE_CASE|Pattern.UNIX_LINES);
		        matcher = pattern.matcher(stringBuffer);
		        
		        if (matcher.find()) {
		        	value = matcher.group(grupoId);
		        }
			}

		} catch (Exception e) {
			logger.error(e);
			// System.out.println(EntityUtils.toString(entity));

		} finally {
			// When HttpClient instance is no longer needed,
			// shut down the connection manager to ensure
			// immediate deallocation of all system resources
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					logger.error(e);
				}
			}
			httpclient.getConnectionManager().shutdown();
		}

		return value;
	}
	
	
	protected String getValue(String tipo,String dato, String regex,Integer grupoId) throws ItemNotFoundException {
		String 		value = "";
		List<String>	values = null;
		values = getValues(tipo, dato, regex, grupoId);
		if(values!=null && !values.isEmpty()){
			value = values.get(0);
		}else{
			throw new ItemNotFoundException("el "+tipo+" no fue encontrado para la regex "+regex+" con groupo id "+grupoId);	
		}
		return value;
	}
	protected List<String> getValues(String tipo,String dato, String regex,Integer grupoId) throws ItemNotFoundException {		
		List<String>	values = new LinkedList<String>();
		String 			value = "";
    	Pattern     	pattern = null;
        Matcher     	matcher = null;
        Boolean			encontrado = Boolean.FALSE;
        
        pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE|Pattern.MULTILINE|Pattern.DOTALL|Pattern.UNICODE_CASE|Pattern.UNIX_LINES);
        matcher = pattern.matcher(dato);
        
        while (matcher.find()) {
        	encontrado = Boolean.TRUE;
        	value = matcher.group(grupoId);
        	if(!values.contains(value)){
        		value = StringEscapeUtils.unescapeHtml(value);
        		values.add(value);
        		logger.info("el valor encontrado es "+value);
        	}else{
        		logger.info("el valor encontrado es "+value+" ya esta en la lista");
        	}
        }
        if(!encontrado){
        	throw new ItemNotFoundException("el "+tipo+" no fue encontrado para la regex "+regex+" con groupo id "+grupoId);
        }
		return values;
	}
	public DataType getDataType() {
		return dataType;
	}
	public void setDataType(DataType dataType) {
		this.dataType = dataType;
	}
	
	
	protected List<String> getValuesWhitoutException(AttributeDataType tipo, String dato, ItemRegex itemRegex, String charset) {
		List<String> values = null;
		try {
			values = getValues(tipo, dato, itemRegex, charset);
		} catch (Exception e) {
			logger.error(e);
		}
		return values;
	}
	protected String getValueWhitoutException(AttributeDataType tipo, String dato, ItemRegex itemRegex, String charset) {
		String value = null;
		try {
			value = getValue(tipo, dato, itemRegex, charset);
		} catch (Exception e) {
			logger.error(e);
		}
		return value;
	}
	protected List<String> getValues(AttributeDataType tipo, String dato, ItemRegex itemRegex, String charset) throws ItemNotFoundException {
		List<String> values= new LinkedList<String>();
		List<String> valuesTmp= new LinkedList<String>();
		String value = "";
		if(!dato.isEmpty()){
			if(itemRegex!=null){
				if(itemRegex.getEnabled()){
					if(itemRegex.getIsStaticValue()){
						valuesTmp.add(itemRegex.getStaticValue());
					}else{
						if(itemRegex.isIndependent()){
							dato = getWebPageContent(itemRegex.getUrl(),itemRegex.getPage(), itemRegex.getRegexPage(), itemRegex.getGroupoIdPage(), charset);
						}
						if(!itemRegex.getRegexData().isEmpty()){
							List<String> datos = null;
						
							datos = getValues(tipo.toString(),dato,itemRegex.getRegexData(),1);
							if(datos!=null && !datos.isEmpty()){								
								for (String item : datos) {
									valuesTmp.addAll(getValuesTmp(tipo, item, itemRegex, charset));
								}
							}

						}else{
							valuesTmp = getValuesTmp(tipo, dato, itemRegex, charset);
						}
					}
					for (String valueItemTmp : valuesTmp) {
						if(managerSinonimos.containsKey(dataType, tipo, value)){
							value = managerSinonimos.getValue(dataType, tipo,value);
						}else{
							value = valueItemTmp;
						}
						logger.info("el valor encontrado es "+value);
						values.add(value);
					}
					
				}else{
					logger.info("el tipo "+tipo+" esta deshabilitado para obtener la informacion");
				}
			}else{
				logger.warn("el tipo "+tipo+" es null para obtener la informacion");
			}
		}else{
			throw new ItemNotFoundException("el dato del "+tipo+" vino vacio");
		}
		if(values.isEmpty()){
			throw new ItemNotFoundException("el "+tipo+" no fue encontrado para la regex ");
		}
		return values;
	}
	private List<String> getValuesTmp(AttributeDataType tipo,String dato,ItemRegex itemRegex,String charset) throws ItemNotFoundException{
		List<String> 	valuesTmp = null;
		String 			value="";
		if(itemRegex.isConditional()){
			valuesTmp = new LinkedList<String>();
			for (String regexConditional : itemRegex.getConditioanlMapKeys()) {
				try{
					value = getValue(tipo.toString(), dato, regexConditional, 0);
					if(!value.isEmpty()){
						value = itemRegex.getConditioanlMapValue(regexConditional);
						if(!valuesTmp.contains(value)){
							valuesTmp.add(value);											
						}
						break;
					}
				}catch (Exception e) {								
				}
			}
			if(value.isEmpty()){
				throw new ItemNotFoundException("el "+tipo+" no fue encontrado para la regex condicionales "+itemRegex.getConditioanlMapKeys()+" del dato "+dato);
			}
		}else{
			valuesTmp = getValues(tipo.toString(), dato, itemRegex.getRegexItem(), itemRegex.getGroupoId());
		}
		return valuesTmp;
	}
	protected String getValue(AttributeDataType tipo,String dato,ItemRegex itemRegex,String charset) throws ItemNotFoundException{
		String value="";
		if(!dato.isEmpty()){
			if(itemRegex!=null){
				if(itemRegex.getEnabled()){
					if(itemRegex.getIsStaticValue()){
						value = itemRegex.getStaticValue();
					}else{
						if(itemRegex.isIndependent()){
							dato = getWebPageContent(itemRegex.getUrl(),itemRegex.getPage(), itemRegex.getRegexPage(), itemRegex.getGroupoIdPage(), charset);
						}
						if(itemRegex.isConditional()){
							for (String regexConditional : itemRegex.getConditioanlMapKeys()) {
								try{
									value = getValue(tipo.toString(), dato, regexConditional, 0);
									if(!value.isEmpty()){
										value = itemRegex.getConditioanlMapValue(regexConditional);
										break;
									}
								}catch (Exception e) {								
								}
							}
							if(value.isEmpty()){
								throw new ItemNotFoundException("el "+tipo+" no fue encontrado para la regex condicionales "+itemRegex.getConditioanlMapKeys()+" del dato "+dato);
							}
						}else{
							value = getValue(tipo.toString(), dato, itemRegex.getRegexItem(), itemRegex.getGroupoId());
						}						
					}
					if(managerSinonimos.containsKey(dataType, tipo, value)){
						value = managerSinonimos.getValue(dataType, tipo,value);
					}
				}else{
					logger.info("el tipo "+tipo+" esta deshabilitado para obtener la informacion");
				}
			}else{
				logger.warn("el tipo "+tipo+" es null para obtener la informacion");
			}
		}else{
			throw new ItemNotFoundException("el dato del "+tipo+" vino vacio");
		}
		value = StringEscapeUtils.unescapeHtml(value);
		logger.info("el valor encontrado es "+value);
		return value;
	}
}
